package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.AdvisedSupport;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.PointcutAdvisor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @Name DefaultAdvisorChainFactory
 * @Description: 默认拦截器链工厂 [实现] 类
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-04-12 17:50:23
 **/
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {
    @Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(AdvisedSupport config, Method method, Class<?> targetClass) {
        // 1. 获取所有切面拦截器（点切表达式 Pointcut + 增强 Advise = PointcutAdvisor extend Advisor）
        Advisor[] advisors = config.getAdvisors().toArray(new Advisor[0]);
        List<Object> interceptors = new ArrayList<>(advisors.length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        for (Advisor advisor : advisors) {
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                // 2. 校验当前 Advisor 是否适用于当前对象
                if (pointcutAdvisor.getPointcut().getClassFilter().filter(actualClass)) {
                    MethodMatcher matcher = pointcutAdvisor.getPointcut().getMethodMatcher();
                    boolean matched = false;
                    // 3. 校验当前 Advisor 是否应用到当前方法上
                    matched = matcher.matches(method, actualClass);
                    if (matched) {
                        // 如果通过校验，则提取切面 advisor 中的 interceptors 增强，添加到 interceptors 中。
                        // 提示：方法拦截器 MethodInterceptor extend 拦截器 Interceptor extend 增强 Advice
                        MethodInterceptor interceptor = (MethodInterceptor) advisor.getAdvice();
                        interceptors.add(interceptor);
                    }
                }
            }
        }
        return interceptors;
    }
}

